
#pragma once


#include "oled_include_pgmspace.hpp"
#include "oled_interface.hpp"

namespace oled_basic {

    template <typename Backend>
    class DriverSSD13xx {
       private:
        Backend *_t(DriverSSD13xx *this_ptr) {
            return reinterpret_cast<Backend *>(this_ptr);
        }

        void _write_cmd(uint_fast8_t cmd) {
            _t(this)->begin_tx(txmode::cmd);
            _t(this)->write(cmd);
            _t(this)->end();
        }

       protected:
        // const OledProperty *_oled = nullptr;

       public:
        // 屏幕旋转180°
        void enable_screen_flip(bool enable) {
            if (enable) {
                _write_cmd(0xC8);  // 反转显示
                _write_cmd(0xA0);
            }
            else {
                _write_cmd(0xC0);  // 正常显示
                _write_cmd(0xA1);
            }
        }

        // 开启OLED显示
        void enable_display(bool enable) {
            if (enable) {
                _write_cmd(0X8D);  // SET DCDC命令
                _write_cmd(0X14);  // DCDC ON
                _write_cmd(0XAF);  // DISPLAY ON
            }
            else {
                _write_cmd(0X8D);  // SET DCDC命令
                _write_cmd(0X10);  // DCDC OFF
                _write_cmd(0XAE);  // DISPLAY OFF
            }
        }

        // 反色显示
        void enable_inverse(bool enable) {
            if (enable) {
                _write_cmd(0xA7);
            }
            else {
                _write_cmd(0xA6);
            }
        }

        /**
         * @brief 设置坐标
         *
         * page addressing 模式，列地址超过127 溢出后自动返回0
         *
         * @param x 列地址
         * @param y 页地址
         */
        void set_cursor(uint_fast8_t column, uint_fast8_t page) {
            _write_cmd(0xb0 + page);
            _write_cmd(((column & 0xf0) >> 4) | 0x10);
            _write_cmd(column & 0x0f);
        }

        /**
         * @brief 屏幕初始化
         *
         * 读取并发送屏幕属性结构里定义的指令列表。
         *
         * 在AVR 或Arduino 平台，使用pgm_read_byte 读取指令列表，指令列表必须带有PROGMEM 标志
         */
        void init_display(const OledProperty &oled) {
            auto len = oled.init_sequence_length;
            auto *ptr = oled.init_sequence;

            for (; len > 0; --len) {
                auto cmd = hide::read_pgm_byte(ptr);
                ++ptr;
                _write_cmd(cmd);
            }
        }
    };

}  // namespace oled_basic